/*******************************************************************

    Copyright(C),2021-2022
    Author: Xiao
    Date: 2022/4/8 20:19

*******************************************************************/

package controller

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	rand2 "math/rand"
	"mcr/pkg/dao"
	"mcr/pkg/logs"
	socket "mcr/pkg/websocket"
	"net/http"
	"strconv"
	"time"
)

// 初始化监听进程
func InitListener() {
	go Listener()
}

// 监听器
func Listener() {
	for {
		time.Sleep(500 * time.Millisecond)
		rs := getRoomList()
		if len(rs) == 0 {
			//logs.Log.Info("暂无房间开启点歌")
			continue
		}
		for _, r := range rs {
			// 有正在播放的
			if s, err := getPlayingSongByRid(r.RoomId); err == nil {
				if s.Song.Mid != 0 {
					//歌曲正在播放
					if time.Now().Unix() < int64(s.Song.Length)+s.Since {
						//预先缓存下一首歌
						preLoadMusicUrl(r)
						continue
					}
					// 歌曲已超时
					if r.RoomType == 4 && r.RoomPlayone == 1 {
						//是单曲循环的电台房间 重置播放时间
						//给true 保留当前房间歌曲
						playSong(r.RoomId, s, true)
						continue
					}
				}
			}
			// 没有正在播放的
			if s, err := getSongFromList(r.RoomId); err == nil {
				if s.Song.Mid != 0 {
					playSong(r.RoomId, s, false)
					continue
				}
			}
			//电台模式
			if r.RoomType == 4 {
				if s, err := getSongByUser(r.RoomUser); err == nil {
					playSong(r.RoomId, s, false)
				}
			} else {
				if r.RoomRobot == 0 {
					if s, err := getSongByRobot(); err == nil {
						playSong(r.RoomId, s, false)
					}
				}
			}
		}
	}
}

// 获取有用户的房间
func getRoomList() []dao.Room {
	if roomStr, err := dao.GetCacheString("RoomList"); err == nil {
		var rs []dao.Room
		err := json.Unmarshal([]byte(roomStr), &rs)
		if err == nil {
			return rs
		}
		logs.Log.Errorf("解码在线房间失败:%s", err)
	}
	rs := dao.GetRooms()
	roomByte, err := json.Marshal(rs)
	if err != nil {
		logs.Log.Errorf("编码在线房间失败:%s", err)
	}
	err = dao.SetCacheString("RoomList", string(roomByte), 5*time.Second)
	if err != nil {
		logs.Log.Errorf("编码在线房间失败:%s", err)
	}
	return rs
}

// 从待放列表中获取音乐
func getSongFromList(rid int) (ListSong, error) {
	var lss []ListSong
	var ls ListSong
	if lssStr, err := dao.GetCacheString(fmt.Sprintf("SongList_%d", rid)); err == nil {
		err = json.Unmarshal([]byte(lssStr), &lss)
		if err != nil {
			logs.Log.Errorf("解析待放歌曲失败:%s", err)
			return ls, fmt.Errorf("解析待放歌曲失败:%s", err)
		}
		if len(lss) > 0 {
			ls = lss[0]
			ls.Since = time.Now().Unix() + 5
			lss = lss[1:]
			lssByte, err := json.Marshal(lss)
			if err != nil {
				logs.Log.Errorf("编码待放歌曲失败:%s", err)
			} else {
				err = dao.SetCacheString(fmt.Sprintf("SongList_%d", rid), string(lssByte), 86400*time.Second)
				if err != nil {
					logs.Log.Errorf("缓存待放歌曲失败:%s", err)
				}
			}
		}
		return ls, nil
	}
	return ls, errors.New("没找到音乐")
}

// 获取正在播放的歌曲
func getPlayingSongByRid(rid int) (ListSong, error) {
	var ls ListSong
	if nowStr, err := dao.GetCacheString(fmt.Sprintf("SongNow_%d", rid)); err == nil {
		err = json.Unmarshal([]byte(nowStr), &ls)
		if err != nil {
			logs.Log.Errorf("解析正在播放的歌曲失败:%s", err)
			return ls, fmt.Errorf("解析正在播放的歌曲失败:%s", err)
		}
		return ls, nil
	}
	return ls, errors.New("没找到音乐")
}

// 获取用户的歌曲
func getSongByUser(uid int) (ListSong, error) {
	var ls ListSong
	u, err := GetUserData(uid)
	if err != nil {
		return ls, fmt.Errorf("没找到电台用户:%s", err)
	}
	ls.User = u
	sl, err := dao.GetUserSongList(uid, true)
	if err != nil {
		return ls, fmt.Errorf("未找到电台用户的音乐:%s", err)
	}
	rand2.Seed(time.Now().UnixMilli())
	s := sl[rand2.Int31n(int32(len(sl))-1)]
	ls.Song = s
	ls.Since = time.Now().Unix()
	return ls, nil
}

// 机器人点的歌曲
func getSongByRobot() (ListSong, error) {
	var ls ListSong
	u, err := GetUserData(1)
	if err != nil {
		return ls, fmt.Errorf("没找到电台用户:%s", err)
	}
	ls.User = u
	// 从热门榜单中随机点一首歌
	bangIdArray := []int{278, 284, 26, 64, 187, 281, 153, 17, 16, 158, 145, 93, 185, 290, 279, 264, 283, 282, 255}
	rand2.Seed(time.Now().UnixMilli())
	bangId := bangIdArray[rand2.Int31n(int32(len(bangIdArray))-1)]
	kwToken := rand2.Int31n(99999999)
	client := &http.Client{}
	url := "http://kuwo.cn/api/www/bang/bang/musicList?pn=1&rn=100&bangId=" + strconv.Itoa(bangId)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		logs.Log.Errorf("查询歌曲失败:%s", err)
		return ls, fmt.Errorf("查询歌曲失败:%s", err)
	}
	req.Header.Set("csrf", fmt.Sprintf("%d", kwToken))
	req.Header.Set("Referer", "http://bd.kuwo.cn")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36")
	req.AddCookie(&http.Cookie{Name: "kw_token", Value: fmt.Sprintf("%d", kwToken)})
	resp, err := client.Do(req)
	if err != nil {
		logs.Log.Errorf("查询歌曲失败:%s", err)
		return ls, fmt.Errorf("查询歌曲失败:%s", err)
	}
	defer resp.Body.Close()
	respByte, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		logs.Log.Errorf("解析歌曲响应:%s", err)
		return ls, fmt.Errorf("解析歌曲响应:%s", err)
	}
	respMap := make(map[string]interface{})
	err = json.Unmarshal(respByte, &respMap)
	if err != nil {
		logs.Log.Errorf("解析歌曲Map:%s", err)
		return ls, fmt.Errorf("解析歌曲响应:%s", err)
	}
	if code, ok := respMap["code"]; ok {
		if code == 200.0 {
			if data, ok := respMap["data"]; ok {
				if list, ok := data.(map[string]interface{})["musicList"]; ok {
					for _, l := range list.([]interface{}) {
						var sr dao.SongResp
						sr.Name = l.(map[string]interface{})["name"].(string)
						sr.Pic = l.(map[string]interface{})["pic"].(string)
						sr.Singer = l.(map[string]interface{})["artist"].(string)
						sr.Length = int(l.(map[string]interface{})["duration"].(float64))
						sr.Mid = int64(l.(map[string]interface{})["rid"].(float64))
						sr.Album = l.(map[string]interface{})["album"].(string)
						srByte, err := json.Marshal(&sr)
						if err != nil {
							logs.Log.Errorf("编码音乐详细信息错误:%s", err)
						}
						err = dao.SetCacheString(fmt.Sprintf("song_detail_%d", sr.Mid), string(srByte), 3600*time.Second)
						if err != nil {
							logs.Log.Errorf("保存音乐详细信息错误:%s", err)
						}
						ls.Song = sr
						break
					}
				}
			}
		}
	} else {
		logs.Log.Errorf("获取歌曲响应失败:%s", respMap["msg"])
		return ls, fmt.Errorf("获取歌曲响应失败:%s", respMap["msg"])
	}
	atMap := make(map[string]interface{})
	atMap["user_id"] = 0
	atMap["user_name"] = "机器人"
	ls.At = atMap
	return ls, nil
}

// 添加音乐至待放列表
func addSongToList(rid int, ls ListSong) {
	sls := GetSongListFromCache(rid)
	isExist := false
	for _, sl := range sls {
		if sl.Song.Mid == ls.Song.Mid {
			isExist = true
			break
		}
	}
	if !isExist {
		sls = append(sls, ls)
		slsByte, err := json.Marshal(sls)
		if err != nil {
			logs.Log.Errorf("编码待放列表失败:%s", err)
		}
		err = dao.SetCacheString(fmt.Sprintf("SongList_%d", rid), string(slsByte), 86400*time.Second)
		if err != nil {
			logs.Log.Errorf("缓存待放列表失败:%s", err)
		}
	}
}

// 缓存音乐
func preLoadMusicUrl(r dao.Room) {
	sls := GetSongListFromCache(r.RoomId)
	have := false
	var now ListSong
	if len(sls) > 0 {
		return
		//now = sls[0]
		//have = true
	} else {
		//电台模式
		if r.RoomType == 4 {
			if s, err := getSongByUser(r.RoomUser); err == nil {
				now = s
				have = true
			}
		} else {
			if r.RoomRobot == 0 {
				if s, err := getSongByRobot(); err == nil {
					now = s
					have = true
				}
			}
		}
		if have {
			addSongToList(r.RoomId, now)
		}
	}
	//if !have {
	//	logs.Log.Error("房间号:%d找不到下一首歌曲", r.RoomId)
	//	return
	//}
	//mid := now.Song.Mid
	//if mid > 0 {
	//	if _, err := dao.GetCacheString(fmt.Sprintf("song_play_temp_url_%d", mid)); err != nil {
	//		preCount := 0
	//		if preCountStr, err := dao.GetCacheString("song_pre_load_count"); err == nil {
	//			if pc, err := strconv.Atoi(preCountStr); err == nil {
	//				preCount = pc
	//			}
	//		}
	//		if preCount < 5 {
	//			preCount++
	//			err = dao.SetCacheString("song_pre_load_count", preCount, 60*time.Second)
	//			if err != nil {
	//				logs.Log.Errorf("缓存音乐数量失败:%s", err)
	//			}
	//
	//		}
	//	}
	//} else {
	//用户自己上传的歌曲 刷新一遍CDN
	//}
}

// 播放音乐
func playSong(rid int, sl ListSong, save bool) {
	sl.Since = time.Now().Unix()
	nowCache := fmt.Sprintf("SongNow_%d", rid)
	slByte, err := json.Marshal(sl)
	if err != nil {
		logs.Log.Errorf("编码正在播放的音乐失败:%s", err)
	} else {
		if save {
			err = dao.SetCacheString(nowCache, string(slByte), 0)
			if err != nil {
				logs.Log.Errorf("缓存正在播放的音乐失败:%s", err)
			}
		} else {
			err = dao.SetCacheString(nowCache, string(slByte), 3600*time.Second)
			if err != nil {
				logs.Log.Errorf("缓存正在播放的音乐失败:%s", err)
			}
		}
		songByte, err := json.Marshal(sl.Song)
		if err == nil {
			err = dao.SetCacheString(fmt.Sprintf("song_detail_%d", sl.Song.Mid), string(songByte), 3600*time.Second)
			if err != nil {
				logs.Log.Errorf("更新正在播放的音乐信息失败:%s", err)
			}
		} else {
			logs.Log.Errorf("更新正在播放的音乐信息时编码失败:%s", err)
		}
	}
	sendMsg := make(map[string]interface{})
	if sl.At == false {
		atMap := make(map[string]interface{})
		atMap["user_id"] = 0
		sl.At = atMap
	}
	sendMsg["at"] = sl.At
	sendMsg["user"] = sl.User
	sendMsg["song"] = sl.Song
	sendMsg["type"] = "playSong"
	sendMsg["since"] = time.Now().Unix()
	sendMsg["count"] = len(GetSongListFromCache(rid))
	sendMsg["time"] = time.Now().Format("15:04:05")
	socket.SendMsgToRoom(rid, sendMsg)
}
